#include <stdio.h>
#include <stdlib.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"
#include "esp_log.h"
#include "esp_timer.h"
#include "esp_rom_sys.h"

#define DHT_GPIO 13
#define TAG "DHT11"

// DHT11时序参数
#define DHT11_WAKEUP_DELAY_MS 18
#define DHT11_BIT_HIGH_MIN_US 50
#define DHT11_TIMEOUT_US 1000

// 全局温湿度变量
static float temperature = 0.0f;
static float humidity = 0.0f;

// 初始化GPIO
static void dht11_init() {
    gpio_config_t io_conf = {
        .pin_bit_mask = (1ULL << DHT_GPIO),
        .mode = GPIO_MODE_INPUT_OUTPUT_OD,
        .pull_up_en = GPIO_PULLUP_ENABLE,
        .pull_down_en = GPIO_PULLDOWN_DISABLE,
        .intr_type = GPIO_INTR_DISABLE,
    };
    gpio_config(&io_conf);
    gpio_set_level(DHT_GPIO, 1);
}

// 高精度微秒延时
static void delay_us(uint32_t us) {
    uint32_t start = esp_timer_get_time();
    while (esp_timer_get_time() - start < us);
}

// 读取DHT11数据
static esp_err_t dht11_read() {
    uint8_t data[5] = {0};
    uint8_t byte = 0;
    uint8_t bit = 0;

    // 发送开始信号
    gpio_set_direction(DHT_GPIO, GPIO_MODE_OUTPUT_OD);
    gpio_set_level(DHT_GPIO, 0);
    esp_rom_delay_us(DHT11_WAKEUP_DELAY_MS * 1000);  // 使用esp_rom_delay_us替代
    gpio_set_level(DHT_GPIO, 1);
    delay_us(40);

    // 切换为输入模式等待响应
    gpio_set_direction(DHT_GPIO, GPIO_MODE_INPUT);

    // 等待DHT11响应低电平
    int64_t start = esp_timer_get_time();
    while (gpio_get_level(DHT_GPIO) == 1) {
        if (esp_timer_get_time() - start > DHT11_TIMEOUT_US) {
            ESP_LOGE(TAG, "DHT11响应超时(低电平)");
            return ESP_ERR_TIMEOUT;
        }
    }

    // 等待DHT11响应高电平
    start = esp_timer_get_time();
    while (gpio_get_level(DHT_GPIO) == 0) {
        if (esp_timer_get_time() - start > DHT11_TIMEOUT_US) {
            ESP_LOGE(TAG, "DHT11响应超时(高电平)");
            return ESP_ERR_TIMEOUT;
        }
    }

    // 读取40位数据
    for (int i = 0; i < 40; i++) {
        // 等待低电平开始位
        start = esp_timer_get_time();
        while (gpio_get_level(DHT_GPIO) == 1) {
            if (esp_timer_get_time() - start > DHT11_TIMEOUT_US) {
                ESP_LOGE(TAG, "数据位开始超时");
                return ESP_ERR_TIMEOUT;
            }
        }

        // 测量高电平持续时间
        start = esp_timer_get_time();
        while (gpio_get_level(DHT_GPIO) == 0) {
            if (esp_timer_get_time() - start > DHT11_TIMEOUT_US) {
                ESP_LOGE(TAG, "数据位低电平超时");
                return ESP_ERR_TIMEOUT;
            }
        }

        int64_t duration = esp_timer_get_time() - start;

        // 判断数据位是0还是1
        if (duration > DHT11_BIT_HIGH_MIN_US) {
            data[byte] |= (1 << (7 - bit));
        }

        bit++;
        if (bit == 8) {
            bit = 0;
            byte++;
        }
    }

    // 校验数据
    if (data[4] == ((data[0] + data[1] + data[2] + data[3]) & 0xFF)) {
        humidity = data[0] + (data[1] * 0.1f);
        temperature = data[2] + (data[3] * 0.1f);
        return ESP_OK;
    } else {
        ESP_LOGE(TAG, "校验和错误");
        return ESP_ERR_INVALID_CRC;
    }
}

// DHT11读取任务
void dht11_task(void *pvParameter) {
    dht11_init();
    
    while (1) {
        esp_err_t err = dht11_read();
        if (err == ESP_OK) {
            ESP_LOGI(TAG, "湿度: %.1f%% 温度: %.1f°C", humidity, temperature);
        } else {
            ESP_LOGE(TAG, "读取DHT11传感器数据失败");
        }
        
        vTaskDelay(pdMS_TO_TICKS(2000)); // 2秒读取一次
    }
}

void app_main() {
    ESP_LOGI(TAG, "DHT11温湿度传感器初始化...");
    xTaskCreate(dht11_task, "dht11_task", 4096, NULL, 5, NULL);
}